home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tcl / tclUtil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-31  |  56.1 KB  |  2,200 lines

  1. /* 
  2.  * tclUtil.c --
  3.  *
  4.  *    This file contains utility procedures that are used by many Tcl
  5.  *    commands.
  6.  *
  7.  * Copyright (c) 1987-1993 The Regents of the University of California.
  8.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * SCCS: @(#) tclUtil.c 1.112 96/02/15 11:42:52
  14.  */
  15.  
  16. #include "tclInt.h"
  17. #include "tclPort.h"
  18.  
  19. /*
  20.  * The following values are used in the flags returned by Tcl_ScanElement
  21.  * and used by Tcl_ConvertElement.  The value TCL_DONT_USE_BRACES is also
  22.  * defined in tcl.h;  make sure its value doesn't overlap with any of the
  23.  * values below.
  24.  *
  25.  * TCL_DONT_USE_BRACES -    1 means the string mustn't be enclosed in
  26.  *                braces (e.g. it contains unmatched braces,
  27.  *                or ends in a backslash character, or user
  28.  *                just doesn't want braces);  handle all
  29.  *                special characters by adding backslashes.
  30.  * USE_BRACES -            1 means the string contains a special
  31.  *                character that can be handled simply by
  32.  *                enclosing the entire argument in braces.
  33.  * BRACES_UNMATCHED -        1 means that braces aren't properly matched
  34.  *                in the argument.
  35.  */
  36.  
  37. #define USE_BRACES        2
  38. #define BRACES_UNMATCHED    4
  39.  
  40. /*
  41.  * Function prototypes for local procedures in this file:
  42.  */
  43.  
  44. static void        SetupAppendBuffer _ANSI_ARGS_((Interp *iPtr,
  45.                 int newSpace));
  46.  
  47. /*
  48.  *----------------------------------------------------------------------
  49.  *
  50.  * TclFindElement --
  51.  *
  52.  *    Given a pointer into a Tcl list, locate the first (or next)
  53.  *    element in the list.
  54.  *
  55.  * Results:
  56.  *    The return value is normally TCL_OK, which means that the
  57.  *    element was successfully located.  If TCL_ERROR is returned
  58.  *    it means that list didn't have proper list structure;
  59.  *    interp->result contains a more detailed error message.
  60.  *
  61.  *    If TCL_OK is returned, then *elementPtr will be set to point
  62.  *    to the first element of list, and *nextPtr will be set to point
  63.  *    to the character just after any white space following the last
  64.  *    character that's part of the element.  If this is the last argument
  65.  *    in the list, then *nextPtr will point to the NULL character at the
  66.  *    end of list.  If sizePtr is non-NULL, *sizePtr is filled in with
  67.  *    the number of characters in the element.  If the element is in
  68.  *    braces, then *elementPtr will point to the character after the
  69.  *    opening brace and *sizePtr will not include either of the braces.
  70.  *    If there isn't an element in the list, *sizePtr will be zero, and
  71.  *    both *elementPtr and *termPtr will refer to the null character at
  72.  *    the end of list.  Note:  this procedure does NOT collapse backslash
  73.  *    sequences.
  74.  *
  75.  * Side effects:
  76.  *    None.
  77.  *
  78.  *----------------------------------------------------------------------
  79.  */
  80.  
  81. int
  82. TclFindElement(interp, list, elementPtr, nextPtr, sizePtr, bracePtr)
  83.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. 
  84.                  * If NULL, then no error message is left
  85.                  * after errors. */
  86.     register char *list;    /* String containing Tcl list with zero
  87.                  * or more elements (possibly in braces). */
  88.     char **elementPtr;        /* Fill in with location of first significant
  89.                  * character in first element of list. */
  90.     char **nextPtr;        /* Fill in with location of character just
  91.                  * after all white space following end of
  92.                  * argument (i.e. next argument or end of
  93.                  * list). */
  94.     int *sizePtr;        /* If non-zero, fill in with size of
  95.                  * element. */
  96.     int *bracePtr;        /* If non-zero fill in with non-zero/zero
  97.                  * to indicate that arg was/wasn't
  98.                  * in braces. */
  99. {
  100.     register char *p;
  101.     int openBraces = 0;
  102.     int inQuotes = 0;
  103.     int size;
  104.  
  105.     /*
  106.      * Skim off leading white space and check for an opening brace or
  107.      * quote.   Note:  use of "isascii" below and elsewhere in this
  108.      * procedure is a temporary hack (7/27/90) because Mx uses characters
  109.      * with the high-order bit set for some things.  This should probably
  110.      * be changed back eventually, or all of Tcl should call isascii.
  111.      */
  112.  
  113.     while (isspace(UCHAR(*list))) {
  114.     list++;
  115.     }
  116. #ifdef STk_CODE
  117.     if (*list == '(') {
  118. #else
  119.     if (*list == '{') {
  120. #endif    
  121.     openBraces = 1;
  122.     list++;
  123.     } else if (*list == '"') {
  124.     inQuotes = 1;
  125.     list++;
  126.     }
  127.     if (bracePtr != 0) {
  128.     *bracePtr = openBraces;
  129.     }
  130.     p = list;
  131.  
  132.     /*
  133.      * Find the end of the element (either a space or a close brace or
  134.      * the end of the string).
  135.      */
  136.  
  137.     while (1) {
  138.     switch (*p) {
  139.  
  140.         /*
  141.          * Open brace: don't treat specially unless the element is
  142.          * in braces.  In this case, keep a nesting count.
  143.          */
  144.  
  145. #ifdef STk_CODE
  146.          case '(':
  147. #else
  148.           case '{':
  149. #endif
  150.         if (openBraces != 0) {
  151.             openBraces++;
  152.         }
  153.         break;
  154.  
  155.         /*
  156.          * Close brace: if element is in braces, keep nesting
  157.          * count and quit when the last close brace is seen.
  158.          */
  159.  
  160. #ifdef STk_CODE
  161.         case ')':
  162. #else
  163.           case '}':
  164. #endif
  165.         if (openBraces == 1) {
  166.             char *p2;
  167.  
  168.             size = p - list;
  169.             p++;
  170.             if (isspace(UCHAR(*p)) || (*p == 0)) {
  171.             goto done;
  172.             }
  173.             for (p2 = p; (*p2 != 0) && (!isspace(UCHAR(*p2)))
  174.                 && (p2 < p+20); p2++) {
  175.             /* null body */
  176.             }
  177.             if (interp != NULL) {
  178.             Tcl_ResetResult(interp);
  179.             sprintf(interp->result,
  180.                 "list element in braces followed by \"%.*s\" instead of space",
  181.                 (int) (p2-p), p);
  182.             }
  183.             return TCL_ERROR;
  184.         } else if (openBraces != 0) {
  185.             openBraces--;
  186.         }
  187.         break;
  188.  
  189.         /*
  190.          * Backslash:  skip over everything up to the end of the
  191.          * backslash sequence.
  192.          */
  193.  
  194.         case '\\': {
  195.         int size;
  196.  
  197.         (void) Tcl_Backslash(p, &size);
  198.         p += size - 1;
  199.         break;
  200.         }
  201.  
  202.         /*
  203.          * Space: ignore if element is in braces or quotes;  otherwise
  204.          * terminate element.
  205.          */
  206.  
  207.         case ' ':
  208.         case '\f':
  209.         case '\n':
  210.         case '\r':
  211.         case '\t':
  212.         case '\v':
  213.         if ((openBraces == 0) && !inQuotes) {
  214.             size = p - list;
  215.             goto done;
  216.         }
  217.         break;
  218.  
  219.         /*
  220.          * Double-quote:  if element is in quotes then terminate it.
  221.          */
  222.  
  223.         case '"':
  224.         if (inQuotes) {
  225.             char *p2;
  226.  
  227.             size = p-list;
  228.             p++;
  229.             if (isspace(UCHAR(*p)) || (*p == 0)) {
  230.             goto done;
  231.             }
  232.             for (p2 = p; (*p2 != 0) && (!isspace(UCHAR(*p2)))
  233.                 && (p2 < p+20); p2++) {
  234.             /* null body */
  235.             }
  236.             if (interp != NULL) {
  237.             Tcl_ResetResult(interp);
  238.             sprintf(interp->result,
  239.                 "list element in quotes followed by \"%.*s\" %s", (int) (p2-p), p,
  240.                 "instead of space");
  241.             }
  242.             return TCL_ERROR;
  243.         }
  244.         break;
  245.  
  246.         /*
  247.          * End of list:  terminate element.
  248.          */
  249.  
  250.         case 0:
  251.         if (openBraces != 0) {
  252.             if (interp != NULL) {
  253.             Tcl_SetResult(interp, "unmatched open brace in list",
  254.                 TCL_STATIC);
  255.             }
  256.             return TCL_ERROR;
  257.         } else if (inQuotes) {
  258.             if (interp != NULL) {
  259.             Tcl_SetResult(interp, "unmatched open quote in list",
  260.                 TCL_STATIC);
  261.             }
  262.             return TCL_ERROR;
  263.         }
  264.         size = p - list;
  265.         goto done;
  266.  
  267.     }
  268.     p++;
  269.     }
  270.  
  271.     done:
  272.     while (isspace(UCHAR(*p))) {
  273.     p++;
  274.     }
  275.     *elementPtr = list;
  276.     *nextPtr = p;
  277.     if (sizePtr != 0) {
  278.     *sizePtr = size;
  279.     }
  280.     return TCL_OK;
  281. }
  282.  
  283. /*
  284.  *----------------------------------------------------------------------
  285.  *
  286.  * TclCopyAndCollapse --
  287.  *
  288.  *    Copy a string and eliminate any backslashes that aren't in braces.
  289.  *
  290.  * Results:
  291.  *    There is no return value.  Count chars. get copied from src
  292.  *    to dst.  Along the way, if backslash sequences are found outside
  293.  *    braces, the backslashes are eliminated in the copy.
  294.  *    After scanning count chars. from source, a null character is
  295.  *    placed at the end of dst.
  296.  *
  297.  * Side effects:
  298.  *    None.
  299.  *
  300.  *----------------------------------------------------------------------
  301.  */
  302.  
  303. void
  304. TclCopyAndCollapse(count, src, dst)
  305.     int count;            /* Total number of characters to copy
  306.                  * from src. */
  307.     register char *src;        /* Copy from here... */
  308.     register char *dst;        /* ... to here. */
  309. {
  310.     register char c;
  311.     int numRead;
  312.  
  313.     for (c = *src; count > 0; src++, c = *src, count--) {
  314.     if (c == '\\') {
  315.         *dst = Tcl_Backslash(src, &numRead);
  316.         dst++;
  317.         src += numRead-1;
  318.         count -= numRead-1;
  319.     } else {
  320.         *dst = c;
  321.         dst++;
  322.     }
  323.     }
  324.     *dst = 0;
  325. }
  326.  
  327. /*
  328.  *----------------------------------------------------------------------
  329.  *
  330.  * Tcl_SplitList --
  331.  *
  332.  *    Splits a list up into its constituent fields.
  333.  *
  334.  * Results
  335.  *    The return value is normally TCL_OK, which means that
  336.  *    the list was successfully split up.  If TCL_ERROR is
  337.  *    returned, it means that "list" didn't have proper list
  338.  *    structure;  interp->result will contain a more detailed
  339.  *    error message.
  340.  *
  341.  *    *argvPtr will be filled in with the address of an array
  342.  *    whose elements point to the elements of list, in order.
  343.  *    *argcPtr will get filled in with the number of valid elements
  344.  *    in the array.  A single block of memory is dynamically allocated
  345.  *    to hold both the argv array and a copy of the list (with
  346.  *    backslashes and braces removed in the standard way).
  347.  *    The caller must eventually free this memory by calling free()
  348.  *    on *argvPtr.  Note:  *argvPtr and *argcPtr are only modified
  349.  *    if the procedure returns normally.
  350.  *
  351.  * Side effects:
  352.  *    Memory is allocated.
  353.  *
  354.  *----------------------------------------------------------------------
  355.  */
  356.  
  357. int
  358. Tcl_SplitList(interp, list, argcPtr, argvPtr)
  359.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. 
  360.                  * If NULL, then no error message is left. */
  361.     char *list;            /* Pointer to string with list structure. */
  362.     int *argcPtr;        /* Pointer to location to fill in with
  363.                  * the number of elements in the list. */
  364.     char ***argvPtr;        /* Pointer to place to store pointer to array
  365.                  * of pointers to list elements. */
  366. {
  367.     char **argv;
  368.     register char *p;
  369.     int size, i, result, elSize, brace;
  370.     char *element;
  371.  
  372.     /*
  373.      * Figure out how much space to allocate.  There must be enough
  374.      * space for both the array of pointers and also for a copy of
  375.      * the list.  To estimate the number of pointers needed, count
  376.      * the number of space characters in the list.
  377.      */
  378.  
  379. #ifdef STk_CODE
  380.     {
  381.       char *q;
  382.  
  383.       for (size = 1, p = q = list; *p != 0; p++) {
  384.     if (isspace(UCHAR(*p))) size++;
  385.     if (*p == ')') q = p; 
  386.       }
  387.  
  388.       /* 
  389.        * Tcl considers strings of the form "( ... )" as quoted string
  390.        * (rather than lists). So if the string is of this form, open
  391.        * and close parenthesis are replaced by spaces
  392.        */
  393.       if (q > list && *list == '(' && *q == ')') {
  394.     *list = *q = ' ';
  395.       }
  396.     }
  397. #else
  398.     for (size = 1, p = list; *p != 0; p++) {
  399.     if (isspace(UCHAR(*p))) {
  400.         size++;
  401.     }
  402.     }
  403. #endif
  404.     size++;            /* Leave space for final NULL pointer. */
  405.     argv = (char **) ckalloc((unsigned)
  406.         ((size * sizeof(char *)) + (p - list) + 1));
  407.     for (i = 0, p = ((char *) argv) + size*sizeof(char *);
  408.         *list != 0; i++) {
  409.     result = TclFindElement(interp, list, &element, &list, &elSize, &brace);
  410.     if (result != TCL_OK) {
  411.         ckfree((char *) argv);
  412.         return result;
  413.     }
  414.     if (*element == 0) {
  415.         break;
  416.     }
  417.     if (i >= size) {
  418.         ckfree((char *) argv);
  419.         if (interp != NULL) {
  420.         Tcl_SetResult(interp, "internal error in Tcl_SplitList",
  421.             TCL_STATIC);
  422.         }
  423.         return TCL_ERROR;
  424.     }
  425.     argv[i] = p;
  426.     if (brace) {
  427.         strncpy(p, element, (size_t) elSize);
  428.         p += elSize;
  429.         *p = 0;
  430.         p++;
  431.     } else {
  432.         TclCopyAndCollapse(elSize, element, p);
  433.         p += elSize+1;
  434.     }
  435.     }
  436.  
  437.     argv[i] = NULL;
  438.     *argvPtr = argv;
  439.     *argcPtr = i;
  440.     return TCL_OK;
  441. }
  442.  
  443. /*
  444.  *----------------------------------------------------------------------
  445.  *
  446.  * Tcl_ScanElement --
  447.  *
  448.  *    This procedure is a companion procedure to Tcl_ConvertElement.
  449.  *    It scans a string to see what needs to be done to it (e.g.
  450.  *    add backslashes or enclosing braces) to make the string into
  451.  *    a valid Tcl list element.
  452.  *
  453.  * Results:
  454.  *    The return value is an overestimate of the number of characters
  455.  *    that will be needed by Tcl_ConvertElement to produce a valid
  456.  *    list element from string.  The word at *flagPtr is filled in
  457.  *    with a value needed by Tcl_ConvertElement when doing the actual
  458.  *    conversion.
  459.  *
  460.  * Side effects:
  461.  *    None.
  462.  *
  463.  *----------------------------------------------------------------------
  464.  */
  465.  
  466. int
  467. Tcl_ScanElement(string, flagPtr)
  468.     char *string;        /* String to convert to Tcl list element. */
  469.     int *flagPtr;        /* Where to store information to guide
  470.                  * Tcl_ConvertElement. */
  471. {
  472.     int flags, nestingLevel;
  473.     register char *p;
  474.  
  475.     /*
  476.      * This procedure and Tcl_ConvertElement together do two things:
  477.      *
  478.      * 1. They produce a proper list, one that will yield back the
  479.      * argument strings when evaluated or when disassembled with
  480.      * Tcl_SplitList.  This is the most important thing.
  481.      * 
  482.      * 2. They try to produce legible output, which means minimizing the
  483.      * use of backslashes (using braces instead).  However, there are
  484.      * some situations where backslashes must be used (e.g. an element
  485.      * like "{abc": the leading brace will have to be backslashed.  For
  486.      * each element, one of three things must be done:
  487.      *
  488.      * (a) Use the element as-is (it doesn't contain anything special
  489.      * characters).  This is the most desirable option.
  490.      *
  491.      * (b) Enclose the element in braces, but leave the contents alone.
  492.      * This happens if the element contains embedded space, or if it
  493.      * contains characters with special interpretation ($, [, ;, or \),
  494.      * or if it starts with a brace or double-quote, or if there are
  495.      * no characters in the element.
  496.      *
  497.      * (c) Don't enclose the element in braces, but add backslashes to
  498.      * prevent special interpretation of special characters.  This is a
  499.      * last resort used when the argument would normally fall under case
  500.      * (b) but contains unmatched braces.  It also occurs if the last
  501.      * character of the argument is a backslash or if the element contains
  502.      * a backslash followed by newline.
  503.      *
  504.      * The procedure figures out how many bytes will be needed to store
  505.      * the result (actually, it overestimates).  It also collects information
  506.      * about the element in the form of a flags word.
  507.      */
  508.  
  509.     nestingLevel = 0;
  510. #ifdef STk_CODE
  511.     flags = TCL_DONT_USE_BRACES;
  512. #else
  513.     flags = 0;
  514. #endif
  515.     if (string == NULL) {
  516.     string = "";
  517.     }
  518.     p = string;
  519.     if ((*p == '{') || (*p == '"') || (*p == 0)) {
  520.     flags |= USE_BRACES;
  521.     }
  522.     for ( ; *p != 0; p++) {
  523.     switch (*p) {
  524.         case '{':
  525.         nestingLevel++;
  526.         break;
  527.         case '}':
  528.         nestingLevel--;
  529.         if (nestingLevel < 0) {
  530.             flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED;
  531.         }
  532.         break;
  533. #ifndef STk_CODE
  534.         case '[':
  535.         case '$':
  536.         case ';':
  537.         case ' ':
  538.         case '\f':
  539.         case '\n':
  540.         case '\r':
  541.         case '\t':
  542.         case '\v':
  543.         flags |= USE_BRACES;
  544.         break;
  545. #endif
  546.         case '\\':
  547.         if ((p[1] == 0) || (p[1] == '\n')) {
  548.             flags = TCL_DONT_USE_BRACES;
  549.         } else {
  550.             int size;
  551.  
  552.             (void) Tcl_Backslash(p, &size);
  553.             p += size-1;
  554.             flags |= USE_BRACES;
  555.         }
  556.         break;
  557.     }
  558.     }
  559.     if (nestingLevel != 0) {
  560.     flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
  561.     }
  562.     *flagPtr = flags;
  563.  
  564.     /*
  565.      * Allow enough space to backslash every character plus leave
  566.      * two spaces for braces.
  567.      */
  568.  
  569.     return 2*(p-string) + 2;
  570. }
  571.  
  572. /*
  573.  *----------------------------------------------------------------------
  574.  *
  575.  * Tcl_ConvertElement --
  576.  *
  577.  *    This is a companion procedure to Tcl_ScanElement.  Given the
  578.  *    information produced by Tcl_ScanElement, this procedure converts
  579.  *    a string to a list element equal to that string.
  580.  *
  581.  * Results:
  582.  *    Information is copied to *dst in the form of a list element
  583.  *    identical to src (i.e. if Tcl_SplitList is applied to dst it
  584.  *    will produce a string identical to src).  The return value is
  585.  *    a count of the number of characters copied (not including the
  586.  *    terminating NULL character).
  587.  *
  588.  * Side effects:
  589.  *    None.
  590.  *
  591.  *----------------------------------------------------------------------
  592.  */
  593.  
  594. int
  595. Tcl_ConvertElement(src, dst, flags)
  596.     register char *src;        /* Source information for list element. */
  597.     char *dst;            /* Place to put list-ified element. */
  598.     int flags;            /* Flags produced by Tcl_ScanElement. */
  599. {
  600.     register char *p = dst;
  601.  
  602.     /*
  603.      * See the comment block at the beginning of the Tcl_ScanElement
  604.      * code for details of how this works.
  605.      */
  606. #ifdef STk_CODE
  607.     if ((src == NULL) || (*src == 0)) {
  608.         p[0] = '\\';
  609.      p[1] = '0';
  610.      p[2] = 0;
  611.      return 2;
  612.     }
  613.     while (*p++ = *src++) /* Nothing */;
  614.     return p - dst - 1;
  615. #else
  616.     if ((src == NULL) || (*src == 0)) {
  617.     p[0] = '{';
  618.     p[1] = '}';
  619.     p[2] = 0;
  620.     return 2;
  621.     }
  622.     if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) {
  623.     *p = '{';
  624.     p++;
  625.     for ( ; *src != 0; src++, p++) {
  626.         *p = *src;
  627.     }
  628.     *p = '}';
  629.     p++;
  630.     } else {
  631.     if (*src == '{') {
  632.         /*
  633.          * Can't have a leading brace unless the whole element is
  634.          * enclosed in braces.  Add a backslash before the brace.
  635.          * Furthermore, this may destroy the balance between open
  636.          * and close braces, so set BRACES_UNMATCHED.
  637.          */
  638.  
  639.         p[0] = '\\';
  640.         p[1] = '{';
  641.         p += 2;
  642.         src++;
  643.         flags |= BRACES_UNMATCHED;
  644.     }
  645.     for (; *src != 0 ; src++) {
  646.         switch (*src) {
  647.         case ']':
  648.         case '[':
  649.         case '$':
  650.         case ';':
  651.         case ' ':
  652.         case '\\':
  653.         case '"':
  654.             *p = '\\';
  655.             p++;
  656.             break;
  657.         case '{':
  658.         case '}':
  659.             /*
  660.              * It may not seem necessary to backslash braces, but
  661.              * it is.  The reason for this is that the resulting
  662.              * list element may actually be an element of a sub-list
  663.              * enclosed in braces (e.g. if Tcl_DStringStartSublist
  664.              * has been invoked), so there may be a brace mismatch
  665.              * if the braces aren't backslashed.
  666.              */
  667.  
  668.             if (flags & BRACES_UNMATCHED) {
  669.             *p = '\\';
  670.             p++;
  671.             }
  672.             break;
  673.         case '\f':
  674.             *p = '\\';
  675.             p++;
  676.             *p = 'f';
  677.             p++;
  678.             continue;
  679.         case '\n':
  680.             *p = '\\';
  681.             p++;
  682.             *p = 'n';
  683.             p++;
  684.             continue;
  685.         case '\r':
  686.             *p = '\\';
  687.             p++;
  688.             *p = 'r';
  689.             p++;
  690.             continue;
  691.         case '\t':
  692.             *p = '\\';
  693.             p++;
  694.             *p = 't';
  695.             p++;
  696.             continue;
  697.         case '\v':
  698.             *p = '\\';
  699.             p++;
  700.             *p = 'v';
  701.             p++;
  702.             continue;
  703.         }
  704.         *p = *src;
  705.         p++;
  706.     }
  707.     }
  708.     *p = '\0';
  709.     return p-dst;
  710. #endif
  711. }
  712.  
  713. /*
  714.  *----------------------------------------------------------------------
  715.  *
  716.  * Tcl_Merge --
  717.  *
  718.  *    Given a collection of strings, merge them together into a
  719.  *    single string that has proper Tcl list structured (i.e.
  720.  *    Tcl_SplitList may be used to retrieve strings equal to the
  721.  *    original elements, and Tcl_Eval will parse the string back
  722.  *    into its original elements).
  723.  *
  724.  * Results:
  725.  *    The return value is the address of a dynamically-allocated
  726.  *    string containing the merged list.
  727.  *
  728.  * Side effects:
  729.  *    None.
  730.  *
  731.  *----------------------------------------------------------------------
  732.  */
  733.  
  734. char *
  735. Tcl_Merge(argc, argv)
  736.     int argc;            /* How many strings to merge. */
  737.     char **argv;        /* Array of string values. */
  738. {
  739. #   define LOCAL_SIZE 20
  740.     int localFlags[LOCAL_SIZE], *flagPtr;
  741.     int numChars;
  742.     char *result;
  743.     register char *dst;
  744.     int i;
  745.  
  746.     /*
  747.      * Pass 1: estimate space, gather flags.
  748.      */
  749.  
  750.     if (argc <= LOCAL_SIZE) {
  751.     flagPtr = localFlags;
  752.     } else {
  753.     flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
  754.     }
  755. #ifdef STk_CODE
  756.     numChars = 3; /* +2 cause of () */
  757. #else
  758.     numChars = 1;
  759. #endif
  760.     for (i = 0; i < argc; i++) {
  761.     numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;
  762.     }
  763.  
  764.     /*
  765.      * Pass two: copy into the result area.
  766.      */
  767.  
  768.     result = (char *) ckalloc((unsigned) numChars);
  769. #ifdef STk_CODE
  770.     *result = '('; dst = result+1;
  771. #else
  772.     dst = result;
  773. #endif
  774.     for (i = 0; i < argc; i++) {
  775.     numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]);
  776.     dst += numChars;
  777.     *dst = ' ';
  778.     dst++;
  779.     }
  780. #ifdef STk_CODE
  781.     if (dst != result+1) dst -= 1;
  782.     dst[0] = ')';
  783.     dst[1] = '\0';
  784. #else
  785.     if (dst == result) {
  786.     *dst = 0;
  787.     } else {
  788.     dst[-1] = 0;
  789.     }
  790. #endif
  791.  
  792.     if (flagPtr != localFlags) {
  793.     ckfree((char *) flagPtr);
  794.     }
  795.     return result;
  796. }
  797.  
  798. /*
  799.  *----------------------------------------------------------------------
  800.  *
  801.  * Tcl_Concat --
  802.  *
  803.  *    Concatenate a set of strings into a single large string.
  804.  *
  805.  * Results:
  806.  *    The return value is dynamically-allocated string containing
  807.  *    a concatenation of all the strings in argv, with spaces between
  808.  *    the original argv elements.
  809.  *
  810.  * Side effects:
  811.  *    Memory is allocated for the result;  the caller is responsible
  812.  *    for freeing the memory.
  813.  *
  814.  *----------------------------------------------------------------------
  815.  */
  816.  
  817. char *
  818. Tcl_Concat(argc, argv)
  819.     int argc;            /* Number of strings to concatenate. */
  820.     char **argv;        /* Array of strings to concatenate. */
  821. {
  822.     int totalSize, i;
  823.     register char *p;
  824.     char *result;
  825.  
  826.     for (totalSize = 1, i = 0; i < argc; i++) {
  827.     totalSize += strlen(argv[i]) + 1;
  828.     }
  829.     result = (char *) ckalloc((unsigned) totalSize);
  830.     if (argc == 0) {
  831.     *result = '\0';
  832.     return result;
  833.     }
  834.     for (p = result, i = 0; i < argc; i++) {
  835.     char *element;
  836.     int length;
  837.  
  838.     /*
  839.      * Clip white space off the front and back of the string
  840.      * to generate a neater result, and ignore any empty
  841.      * elements.
  842.      */
  843.  
  844.     element = argv[i];
  845.     while (isspace(UCHAR(*element))) {
  846.         element++;
  847.     }
  848.     for (length = strlen(element);
  849.         (length > 0) && (isspace(UCHAR(element[length-1])));
  850.         length--) {
  851.         /* Null loop body. */
  852.     }
  853.     if (length == 0) {
  854.         continue;
  855.     }
  856.     (void) strncpy(p, element, (size_t) length);
  857.     p += length;
  858.     *p = ' ';
  859.     p++;
  860.     }
  861.     if (p != result) {
  862.     p[-1] = 0;
  863.     } else {
  864.     *p = 0;
  865.     }
  866.     return result;
  867. }
  868.  
  869. /*
  870.  *----------------------------------------------------------------------
  871.  *
  872.  * Tcl_StringMatch --
  873.  *
  874.  *    See if a particular string matches a particular pattern.
  875.  *
  876.  * Results:
  877.  *    The return value is 1 if string matches pattern, and
  878.  *    0 otherwise.  The matching operation permits the following
  879.  *    special characters in the pattern: *?\[] (see the manual
  880.  *    entry for details on what these mean).
  881.  *
  882.  * Side effects:
  883.  *    None.
  884.  *
  885.  *----------------------------------------------------------------------
  886.  */
  887.  
  888. int
  889. Tcl_StringMatch(string, pattern)
  890.     register char *string;    /* String. */
  891.     register char *pattern;    /* Pattern, which may contain
  892.                  * special characters. */
  893. {
  894.     char c2;
  895.  
  896.     while (1) {
  897.     /* See if we're at the end of both the pattern and the string.
  898.      * If so, we succeeded.  If we're at the end of the pattern
  899.      * but not at the end of the string, we failed.
  900.      */
  901.     
  902.     if (*pattern == 0) {
  903.         if (*string == 0) {
  904.         return 1;
  905.         } else {
  906.         return 0;
  907.         }
  908.     }
  909.     if ((*string == 0) && (*pattern != '*')) {
  910.         return 0;
  911.     }
  912.  
  913.     /* Check for a "*" as the next pattern character.  It matches
  914.      * any substring.  We handle this by calling ourselves
  915.      * recursively for each postfix of string, until either we
  916.      * match or we reach the end of the string.
  917.      */
  918.     
  919.     if (*pattern == '*') {
  920.         pattern += 1;
  921.         if (*pattern == 0) {
  922.         return 1;
  923.         }
  924.         while (1) {
  925.         if (Tcl_StringMatch(string, pattern)) {
  926.             return 1;
  927.         }
  928.         if (*string == 0) {
  929.             return 0;
  930.         }
  931.         string += 1;
  932.         }
  933.     }
  934.     
  935.     /* Check for a "?" as the next pattern character.  It matches
  936.      * any single character.
  937.      */
  938.  
  939.     if (*pattern == '?') {
  940.         goto thisCharOK;
  941.     }
  942.  
  943.     /* Check for a "[" as the next pattern character.  It is followed
  944.      * by a list of characters that are acceptable, or by a range
  945.      * (two characters separated by "-").
  946.      */
  947.     
  948.     if (*pattern == '[') {
  949.         pattern += 1;
  950.         while (1) {
  951.         if ((*pattern == ']') || (*pattern == 0)) {
  952.             return 0;
  953.         }
  954.         if (*pattern == *string) {
  955.             break;
  956.         }
  957.         if (pattern[1] == '-') {
  958.             c2 = pattern[2];
  959.             if (c2 == 0) {
  960.             return 0;
  961.             }
  962.             if ((*pattern <= *string) && (c2 >= *string)) {
  963.             break;
  964.             }
  965.             if ((*pattern >= *string) && (c2 <= *string)) {
  966.             break;
  967.             }
  968.             pattern += 2;
  969.         }
  970.         pattern += 1;
  971.         }
  972.         while (*pattern != ']') {
  973.         if (*pattern == 0) {
  974.             pattern--;
  975.             break;
  976.         }
  977.         pattern += 1;
  978.         }
  979.         goto thisCharOK;
  980.     }
  981.     
  982.     /* If the next pattern character is '/', just strip off the '/'
  983.      * so we do exact matching on the character that follows.
  984.      */
  985.     
  986.     if (*pattern == '\\') {
  987.         pattern += 1;
  988.         if (*pattern == 0) {
  989.         return 0;
  990.         }
  991.     }
  992.  
  993.     /* There's no special character.  Just make sure that the next
  994.      * characters of each string match.
  995.      */
  996.     
  997.     if (*pattern != *string) {
  998.         return 0;
  999.     }
  1000.  
  1001.     thisCharOK: pattern += 1;
  1002.     string += 1;
  1003.     }
  1004. }
  1005.  
  1006. /*
  1007.  *----------------------------------------------------------------------
  1008.  *
  1009.  * Tcl_SetResult --
  1010.  *
  1011.  *    Arrange for "string" to be the Tcl return value.
  1012.  *
  1013.  * Results:
  1014.  *    None.
  1015.  *
  1016.  * Side effects:
  1017.  *    interp->result is left pointing either to "string" (if "copy" is 0)
  1018.  *    or to a copy of string.
  1019.  *
  1020.  *----------------------------------------------------------------------
  1021.  */
  1022.  
  1023. void
  1024. Tcl_SetResult(interp, string, freeProc)
  1025.     Tcl_Interp *interp;        /* Interpreter with which to associate the
  1026.                  * return value. */
  1027.     char *string;        /* Value to be returned.  If NULL,
  1028.                  * the result is set to an empty string. */
  1029.     Tcl_FreeProc *freeProc;    /* Gives information about the string:
  1030.                  * TCL_STATIC, TCL_VOLATILE, or the address
  1031.                  * of a Tcl_FreeProc such as free. */
  1032. {
  1033.     register Interp *iPtr = (Interp *) interp;
  1034.     int length;
  1035.     Tcl_FreeProc *oldFreeProc = iPtr->freeProc;
  1036.     char *oldResult = iPtr->result;
  1037.  
  1038.     if (string == NULL) {
  1039.     iPtr->resultSpace[0] = 0;
  1040.     iPtr->result = iPtr->resultSpace;
  1041.     iPtr->freeProc = 0;
  1042.     } else if (freeProc == TCL_DYNAMIC) {
  1043.     iPtr->result = string;
  1044.     iPtr->freeProc = TCL_DYNAMIC;
  1045.     } else if (freeProc == TCL_VOLATILE) {
  1046.     length = strlen(string);
  1047.     if (length > TCL_RESULT_SIZE) {
  1048.         iPtr->result = (char *) ckalloc((unsigned) length+1);
  1049.         iPtr->freeProc = TCL_DYNAMIC;
  1050.     } else {
  1051.         iPtr->result = iPtr->resultSpace;
  1052.         iPtr->freeProc = 0;
  1053.     }
  1054.     strcpy(iPtr->result, string);
  1055.     } else {
  1056.     iPtr->result = string;
  1057.     iPtr->freeProc = freeProc;
  1058.     }
  1059.  
  1060.     /*
  1061.      * If the old result was dynamically-allocated, free it up.  Do it
  1062.      * here, rather than at the beginning, in case the new result value
  1063.      * was part of the old result value.
  1064.      */
  1065.  
  1066.     if (oldFreeProc != 0) {
  1067.     if ((oldFreeProc == TCL_DYNAMIC)
  1068.         || (oldFreeProc == (Tcl_FreeProc *) free)) {
  1069.         ckfree(oldResult);
  1070.     } else {
  1071.         (*oldFreeProc)(oldResult);
  1072.     }
  1073.     }
  1074. }
  1075.  
  1076. /*
  1077.  *----------------------------------------------------------------------
  1078.  *
  1079.  * Tcl_AppendResult --
  1080.  *
  1081.  *    Append a variable number of strings onto the result already
  1082.  *    present for an interpreter.
  1083.  *
  1084.  * Results:
  1085.  *    None.
  1086.  *
  1087.  * Side effects:
  1088.  *    The result in the interpreter given by the first argument
  1089.  *    is extended by the strings given by the second and following
  1090.  *    arguments (up to a terminating NULL argument).
  1091.  *
  1092.  *----------------------------------------------------------------------
  1093.  */
  1094.  
  1095.     /* VARARGS2 */
  1096. void
  1097. Tcl_AppendResult TCL_VARARGS_DEF(Tcl_Interp *,arg1)
  1098. {
  1099.     va_list argList;
  1100.     register Interp *iPtr;
  1101.     char *string;
  1102.     int newSpace;
  1103.  
  1104.     /*
  1105.      * First, scan through all the arguments to see how much space is
  1106.      * needed.
  1107.      */
  1108.  
  1109.     iPtr = (Interp *) TCL_VARARGS_START(Tcl_Interp *,arg1,argList);
  1110.     newSpace = 0;
  1111.     while (1) {
  1112.     string = va_arg(argList, char *);
  1113.     if (string == NULL) {
  1114.         break;
  1115.     }
  1116.     newSpace += strlen(string);
  1117.     }
  1118.     va_end(argList);
  1119.  
  1120.     /*
  1121.      * If the append buffer isn't already setup and large enough
  1122.      * to hold the new data, set it up.
  1123.      */
  1124.  
  1125.     if ((iPtr->result != iPtr->appendResult)
  1126.         || (iPtr->appendResult[iPtr->appendUsed] != 0)
  1127.         || ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) {
  1128.        SetupAppendBuffer(iPtr, newSpace);
  1129.     }
  1130.  
  1131.     /*
  1132.      * Final step:  go through all the argument strings again, copying
  1133.      * them into the buffer.
  1134.      */
  1135.  
  1136.     TCL_VARARGS_START(Tcl_Interp *,arg1,argList);
  1137.     while (1) {
  1138.     string = va_arg(argList, char *);
  1139.     if (string == NULL) {
  1140.         break;
  1141.     }
  1142.     strcpy(iPtr->appendResult + iPtr->appendUsed, string);
  1143.     iPtr->appendUsed += strlen(string);
  1144.     }
  1145.     va_end(argList);
  1146. }
  1147.  
  1148. /*
  1149.  *----------------------------------------------------------------------
  1150.  *
  1151.  * Tcl_AppendElement --
  1152.  *
  1153.  *    Convert a string to a valid Tcl list element and append it
  1154.  *    to the current result (which is ostensibly a list).
  1155.  *
  1156.  * Results:
  1157.  *    None.
  1158.  *
  1159.  * Side effects:
  1160.  *    The result in the interpreter given by the first argument
  1161.  *    is extended with a list element converted from string.  A
  1162.  *    separator space is added before the converted list element
  1163.  *    unless the current result is empty, contains the single
  1164.  *    character "{", or ends in " {".
  1165.  *
  1166.  *----------------------------------------------------------------------
  1167.  */
  1168.  
  1169. void
  1170. Tcl_AppendElement(interp, string)
  1171.     Tcl_Interp *interp;        /* Interpreter whose result is to be
  1172.                  * extended. */
  1173.     char *string;        /* String to convert to list element and
  1174.                  * add to result. */
  1175. {
  1176.     register Interp *iPtr = (Interp *) interp;
  1177.     int size, flags;
  1178.     char *dst;
  1179.  
  1180.     /*
  1181.      * See how much space is needed, and grow the append buffer if
  1182.      * needed to accommodate the list element.
  1183.      */
  1184.  
  1185.     size = Tcl_ScanElement(string, &flags) + 1;
  1186.     if ((iPtr->result != iPtr->appendResult)
  1187.         || (iPtr->appendResult[iPtr->appendUsed] != 0)
  1188.         || ((size + iPtr->appendUsed) >= iPtr->appendAvl)) {
  1189.        SetupAppendBuffer(iPtr, size+iPtr->appendUsed);
  1190.     }
  1191.  
  1192.     /*
  1193.      * Convert the string into a list element and copy it to the
  1194.      * buffer that's forming, with a space separator if needed.
  1195.      */
  1196.  
  1197.     dst = iPtr->appendResult + iPtr->appendUsed;
  1198.     if (TclNeedSpace(iPtr->appendResult, dst)) {
  1199.     iPtr->appendUsed++;
  1200.     *dst = ' ';
  1201.     dst++;
  1202.     }
  1203.     iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags);
  1204. }
  1205.  
  1206. /*
  1207.  *----------------------------------------------------------------------
  1208.  *
  1209.  * SetupAppendBuffer --
  1210.  *
  1211.  *    This procedure makes sure that there is an append buffer
  1212.  *    properly initialized for interp, and that it has at least
  1213.  *    enough room to accommodate newSpace new bytes of information.
  1214.  *
  1215.  * Results:
  1216.  *    None.
  1217.  *
  1218.  * Side effects:
  1219.  *    None.
  1220.  *
  1221.  *----------------------------------------------------------------------
  1222.  */
  1223.  
  1224. static void
  1225. SetupAppendBuffer(iPtr, newSpace)
  1226.     register Interp *iPtr;    /* Interpreter whose result is being set up. */
  1227.     int newSpace;        /* Make sure that at least this many bytes
  1228.                  * of new information may be added. */
  1229. {
  1230.     int totalSpace;
  1231.  
  1232.     /*
  1233.      * Make the append buffer larger, if that's necessary, then
  1234.      * copy the current result into the append buffer and make the
  1235.      * append buffer the official Tcl result.
  1236.      */
  1237.  
  1238.     if (iPtr->result != iPtr->appendResult) {
  1239.     /*
  1240.      * If an oversized buffer was used recently, then free it up
  1241.      * so we go back to a smaller buffer.  This avoids tying up
  1242.      * memory forever after a large operation.
  1243.      */
  1244.  
  1245.     if (iPtr->appendAvl > 500) {
  1246.         ckfree(iPtr->appendResult);
  1247.         iPtr->appendResult = NULL;
  1248.         iPtr->appendAvl = 0;
  1249.     }
  1250.     iPtr->appendUsed = strlen(iPtr->result);
  1251.     } else if (iPtr->result[iPtr->appendUsed] != 0) {
  1252.     /*
  1253.      * Most likely someone has modified a result created by
  1254.      * Tcl_AppendResult et al. so that it has a different size.
  1255.      * Just recompute the size.
  1256.      */
  1257.  
  1258.     iPtr->appendUsed = strlen(iPtr->result);
  1259.     }
  1260.     totalSpace = newSpace + iPtr->appendUsed;
  1261.     if (totalSpace >= iPtr->appendAvl) {
  1262.     char *new;
  1263.  
  1264.     if (totalSpace < 100) {
  1265.         totalSpace = 200;
  1266.     } else {
  1267.         totalSpace *= 2;
  1268.     }
  1269.     new = (char *) ckalloc((unsigned) totalSpace);
  1270.     strcpy(new, iPtr->result);
  1271.     if (iPtr->appendResult != NULL) {
  1272.         ckfree(iPtr->appendResult);
  1273.     }
  1274.     iPtr->appendResult = new;
  1275.     iPtr->appendAvl = totalSpace;
  1276.     } else if (iPtr->result != iPtr->appendResult) {
  1277.     strcpy(iPtr->appendResult, iPtr->result);
  1278.     }
  1279.     Tcl_FreeResult(iPtr);
  1280.     iPtr->result = iPtr->appendResult;
  1281. }
  1282.  
  1283. /*
  1284.  *----------------------------------------------------------------------
  1285.  *
  1286.  * Tcl_ResetResult --
  1287.  *
  1288.  *    This procedure restores the result area for an interpreter
  1289.  *    to its default initialized state, freeing up any memory that
  1290.  *    may have been allocated for the result and clearing any
  1291.  *    error information for the interpreter.
  1292.  *
  1293.  * Results:
  1294.  *    None.
  1295.  *
  1296.  * Side effects:
  1297.  *    None.
  1298.  *
  1299.  *----------------------------------------------------------------------
  1300.  */
  1301.  
  1302. void
  1303. Tcl_ResetResult(interp)
  1304.     Tcl_Interp *interp;        /* Interpreter for which to clear result. */
  1305. {
  1306.     register Interp *iPtr = (Interp *) interp;
  1307.  
  1308.     Tcl_FreeResult(iPtr);
  1309.     iPtr->result = iPtr->resultSpace;
  1310.     iPtr->resultSpace[0] = 0;
  1311.     iPtr->flags &=
  1312.         ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET);
  1313. }
  1314.  
  1315. /*
  1316.  *----------------------------------------------------------------------
  1317.  *
  1318.  * Tcl_SetErrorCode --
  1319.  *
  1320.  *    This procedure is called to record machine-readable information
  1321.  *    about an error that is about to be returned.
  1322.  *
  1323.  * Results:
  1324.  *    None.
  1325.  *
  1326.  * Side effects:
  1327.  *    The errorCode global variable is modified to hold all of the
  1328.  *    arguments to this procedure, in a list form with each argument
  1329.  *    becoming one element of the list.  A flag is set internally
  1330.  *    to remember that errorCode has been set, so the variable doesn't
  1331.  *    get set automatically when the error is returned.
  1332.  *
  1333.  *----------------------------------------------------------------------
  1334.  */
  1335.     /* VARARGS2 */
  1336. void
  1337. Tcl_SetErrorCode TCL_VARARGS_DEF(Tcl_Interp *,arg1)
  1338. {
  1339.     va_list argList;
  1340.     char *string;
  1341.     int flags;
  1342.     Interp *iPtr;
  1343.  
  1344.     /*
  1345.      * Scan through the arguments one at a time, appending them to
  1346.      * $errorCode as list elements.
  1347.      */
  1348.  
  1349.     iPtr = (Interp *) TCL_VARARGS_START(Tcl_Interp *,arg1,argList);
  1350.     flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT;
  1351.     while (1) {
  1352.     string = va_arg(argList, char *);
  1353.     if (string == NULL) {
  1354.         break;
  1355.     }
  1356.     (void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode",
  1357.         (char *) NULL, string, flags);
  1358.     flags |= TCL_APPEND_VALUE;
  1359.     }
  1360.     va_end(argList);
  1361.     iPtr->flags |= ERROR_CODE_SET;
  1362. }
  1363.  
  1364. #ifndef STk_CODE
  1365. /*
  1366.  *----------------------------------------------------------------------
  1367.  *
  1368.  * TclGetListIndex --
  1369.  *
  1370.  *    Parse a list index, which may be either an integer or the
  1371.  *    value "end".
  1372.  *
  1373.  * Results:
  1374.  *    The return value is either TCL_OK or TCL_ERROR.  If it is
  1375.  *    TCL_OK, then the index corresponding to string is left in
  1376.  *    *indexPtr.  If the return value is TCL_ERROR, then string
  1377.  *    was bogus;  an error message is returned in interp->result.
  1378.  *    If a negative index is specified, it is rounded up to 0.
  1379.  *    The index value may be larger than the size of the list
  1380.  *    (this happens when "end" is specified).
  1381.  *
  1382.  * Side effects:
  1383.  *    None.
  1384.  *
  1385.  *----------------------------------------------------------------------
  1386.  */
  1387.  
  1388. int
  1389. TclGetListIndex(interp, string, indexPtr)
  1390.     Tcl_Interp *interp;            /* Interpreter for error reporting. */
  1391.     char *string;            /* String containing list index. */
  1392.     int *indexPtr;            /* Where to store index. */
  1393. {
  1394.     if (isdigit(UCHAR(*string)) || (*string == '-')) {
  1395.     if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) {
  1396.         return TCL_ERROR;
  1397.     }
  1398.     if (*indexPtr < 0) {
  1399.         *indexPtr = 0;
  1400.     }
  1401.     } else if (strncmp(string, "end", strlen(string)) == 0) {
  1402.     *indexPtr = INT_MAX;
  1403.     } else {
  1404.     Tcl_AppendResult(interp, "bad index \"", string,
  1405.         "\": must be integer or \"end\"", (char *) NULL);
  1406.     return TCL_ERROR;
  1407.     }
  1408.     return TCL_OK;
  1409. }
  1410. #endif
  1411.  
  1412. /*
  1413.  *----------------------------------------------------------------------
  1414.  *
  1415.  * Tcl_RegExpCompile --
  1416.  *
  1417.  *    Compile a regular expression into a form suitable for fast
  1418.  *    matching.  This procedure retains a small cache of pre-compiled
  1419.  *    regular expressions in the interpreter, in order to avoid
  1420.  *    compilation costs as much as possible.
  1421.  *
  1422.  * Results:
  1423.  *    The return value is a pointer to the compiled form of string,
  1424.  *    suitable for passing to Tcl_RegExpExec.  This compiled form
  1425.  *    is only valid up until the next call to this procedure, so
  1426.  *    don't keep these around for a long time!  If an error occurred
  1427.  *    while compiling the pattern, then NULL is returned and an error
  1428.  *    message is left in interp->result.
  1429.  *
  1430.  * Side effects:
  1431.  *    The cache of compiled regexp's in interp will be modified to
  1432.  *    hold information for string, if such information isn't already
  1433.  *    present in the cache.
  1434.  *
  1435.  *----------------------------------------------------------------------
  1436.  */
  1437.  
  1438. Tcl_RegExp
  1439. Tcl_RegExpCompile(interp, string)
  1440.     Tcl_Interp *interp;            /* For use in error reporting. */
  1441.     char *string;            /* String for which to produce
  1442.                      * compiled regular expression. */
  1443. {
  1444.     register Interp *iPtr = (Interp *) interp;
  1445.     int i, length;
  1446.     regexp *result;
  1447.  
  1448.     length = strlen(string);
  1449.     for (i = 0; i < NUM_REGEXPS; i++) {
  1450.     if ((length == iPtr->patLengths[i])
  1451.         && (strcmp(string, iPtr->patterns[i]) == 0)) {
  1452.         /*
  1453.          * Move the matched pattern to the first slot in the
  1454.          * cache and shift the other patterns down one position.
  1455.          */
  1456.  
  1457.         if (i != 0) {
  1458.         int j;
  1459.         char *cachedString;
  1460.  
  1461.         cachedString = iPtr->patterns[i];
  1462.         result = iPtr->regexps[i];
  1463.         for (j = i-1; j >= 0; j--) {
  1464.             iPtr->patterns[j+1] = iPtr->patterns[j];
  1465.             iPtr->patLengths[j+1] = iPtr->patLengths[j];
  1466.             iPtr->regexps[j+1] = iPtr->regexps[j];
  1467.         }
  1468.         iPtr->patterns[0] = cachedString;
  1469.         iPtr->patLengths[0] = length;
  1470.         iPtr->regexps[0] = result;
  1471.         }
  1472.         return (Tcl_RegExp) iPtr->regexps[0];
  1473.     }
  1474.     }
  1475.  
  1476.     /*
  1477.      * No match in the cache.  Compile the string and add it to the
  1478.      * cache.
  1479.      */
  1480.  
  1481.     TclRegError((char *) NULL);
  1482.     result = TclRegComp(string);
  1483.     if (TclGetRegError() != NULL) {
  1484.     Tcl_AppendResult(interp,
  1485.         "couldn't compile regular expression pattern: ",
  1486.         TclGetRegError(), (char *) NULL);
  1487.     return NULL;
  1488.     }
  1489.     if (iPtr->patterns[NUM_REGEXPS-1] != NULL) {
  1490.     ckfree(iPtr->patterns[NUM_REGEXPS-1]);
  1491.     ckfree((char *) iPtr->regexps[NUM_REGEXPS-1]);
  1492.     }
  1493.     for (i = NUM_REGEXPS - 2; i >= 0; i--) {
  1494.     iPtr->patterns[i+1] = iPtr->patterns[i];
  1495.     iPtr->patLengths[i+1] = iPtr->patLengths[i];
  1496.     iPtr->regexps[i+1] = iPtr->regexps[i];
  1497.     }
  1498.     iPtr->patterns[0] = (char *) ckalloc((unsigned) (length+1));
  1499.     strcpy(iPtr->patterns[0], string);
  1500.     iPtr->patLengths[0] = length;
  1501.     iPtr->regexps[0] = result;
  1502.     return (Tcl_RegExp) result;
  1503. }
  1504.  
  1505. /*
  1506.  *----------------------------------------------------------------------
  1507.  *
  1508.  * Tcl_RegExpExec --
  1509.  *
  1510.  *    Execute the regular expression matcher using a compiled form
  1511.  *    of a regular expression and save information about any match
  1512.  *    that is found.
  1513.  *
  1514.  * Results:
  1515.  *    If an error occurs during the matching operation then -1
  1516.  *    is returned and interp->result contains an error message.
  1517.  *    Otherwise the return value is 1 if a matching range is
  1518.  *    found and 0 if there is no matching range.
  1519.  *
  1520.  * Side effects:
  1521.  *    None.
  1522.  *
  1523.  *----------------------------------------------------------------------
  1524.  */
  1525.  
  1526. int
  1527. Tcl_RegExpExec(interp, re, string, start)
  1528.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  1529.     Tcl_RegExp re;        /* Compiled regular expression;  must have
  1530.                  * been returned by previous call to
  1531.                  * Tcl_RegExpCompile. */
  1532.     char *string;        /* String against which to match re. */
  1533.     char *start;        /* If string is part of a larger string,
  1534.                  * this identifies beginning of larger
  1535.                  * string, so that "^" won't match. */
  1536. {
  1537.     int match;
  1538.  
  1539.     regexp *regexpPtr = (regexp *) re;
  1540.     TclRegError((char *) NULL);
  1541.     match = TclRegExec(regexpPtr, string, start);
  1542.     if (TclGetRegError() != NULL) {
  1543.     Tcl_ResetResult(interp);
  1544.     Tcl_AppendResult(interp, "error while matching regular expression: ",
  1545.         TclGetRegError(), (char *) NULL);
  1546.     return -1;
  1547.     }
  1548.     return match;
  1549. }
  1550.  
  1551. /*
  1552.  *----------------------------------------------------------------------
  1553.  *
  1554.  * Tcl_RegExpRange --
  1555.  *
  1556.  *    Returns pointers describing the range of a regular expression match,
  1557.  *    or one of the subranges within the match.
  1558.  *
  1559.  * Results:
  1560.  *    The variables at *startPtr and *endPtr are modified to hold the
  1561.  *    addresses of the endpoints of the range given by index.  If the
  1562.  *    specified range doesn't exist then NULLs are returned.
  1563.  *
  1564.  * Side effects:
  1565.  *    None.
  1566.  *
  1567.  *----------------------------------------------------------------------
  1568.  */
  1569.  
  1570. void
  1571. Tcl_RegExpRange(re, index, startPtr, endPtr)
  1572.     Tcl_RegExp re;        /* Compiled regular expression that has
  1573.                  * been passed to Tcl_RegExpExec. */
  1574.     int index;            /* 0 means give the range of the entire
  1575.                  * match, > 0 means give the range of
  1576.                  * a matching subrange.  Must be no greater
  1577.                  * than NSUBEXP. */
  1578.     char **startPtr;        /* Store address of first character in
  1579.                  * (sub-) range here. */
  1580.     char **endPtr;        /* Store address of character just after last
  1581.                  * in (sub-) range here. */
  1582. {
  1583.     regexp *regexpPtr = (regexp *) re;
  1584.  
  1585.     if (index >= NSUBEXP) {
  1586.     *startPtr = *endPtr = NULL;
  1587.     } else {
  1588.     *startPtr = regexpPtr->startp[index];
  1589.     *endPtr = regexpPtr->endp[index];
  1590.     }
  1591. }
  1592.  
  1593. /*
  1594.  *----------------------------------------------------------------------
  1595.  *
  1596.  * Tcl_RegExpMatch --
  1597.  *
  1598.  *    See if a string matches a regular expression.
  1599.  *
  1600.  * Results:
  1601.  *    If an error occurs during the matching operation then -1
  1602.  *    is returned and interp->result contains an error message.
  1603.  *    Otherwise the return value is 1 if "string" matches "pattern"
  1604.  *    and 0 otherwise.
  1605.  *
  1606.  * Side effects:
  1607.  *    None.
  1608.  *
  1609.  *----------------------------------------------------------------------
  1610.  */
  1611.  
  1612. int
  1613. Tcl_RegExpMatch(interp, string, pattern)
  1614.     Tcl_Interp *interp;        /* Used for error reporting. */
  1615.     char *string;        /* String. */
  1616.     char *pattern;        /* Regular expression to match against
  1617.                  * string. */
  1618. {
  1619.     Tcl_RegExp re;
  1620.  
  1621.     re = Tcl_RegExpCompile(interp, pattern);
  1622.     if (re == NULL) {
  1623.     return -1;
  1624.     }
  1625.     return Tcl_RegExpExec(interp, re, string, string);
  1626. }
  1627.  
  1628. /*
  1629.  *----------------------------------------------------------------------
  1630.  *
  1631.  * Tcl_DStringInit --
  1632.  *
  1633.  *    Initializes a dynamic string, discarding any previous contents
  1634.  *    of the string (Tcl_DStringFree should have been called already
  1635.  *    if the dynamic string was previously in use).
  1636.  *
  1637.  * Results:
  1638.  *    None.
  1639.  *
  1640.  * Side effects:
  1641.  *    The dynamic string is initialized to be empty.
  1642.  *
  1643.  *----------------------------------------------------------------------
  1644.  */
  1645.  
  1646. void
  1647. Tcl_DStringInit(dsPtr)
  1648.     register Tcl_DString *dsPtr;    /* Pointer to structure for
  1649.                      * dynamic string. */
  1650. {
  1651.     dsPtr->string = dsPtr->staticSpace;
  1652.     dsPtr->length = 0;
  1653.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1654.     dsPtr->staticSpace[0] = 0;
  1655. }
  1656.  
  1657. /*
  1658.  *----------------------------------------------------------------------
  1659.  *
  1660.  * Tcl_DStringAppend --
  1661.  *
  1662.  *    Append more characters to the current value of a dynamic string.
  1663.  *
  1664.  * Results:
  1665.  *    The return value is a pointer to the dynamic string's new value.
  1666.  *
  1667.  * Side effects:
  1668.  *    Length bytes from string (or all of string if length is less
  1669.  *    than zero) are added to the current value of the string.  Memory
  1670.  *    gets reallocated if needed to accomodate the string's new size.
  1671.  *
  1672.  *----------------------------------------------------------------------
  1673.  */
  1674.  
  1675. char *
  1676. Tcl_DStringAppend(dsPtr, string, length)
  1677.     register Tcl_DString *dsPtr;    /* Structure describing dynamic
  1678.                      * string. */
  1679.     char *string;            /* String to append.  If length is
  1680.                      * -1 then this must be
  1681.                      * null-terminated. */
  1682.     int length;                /* Number of characters from string
  1683.                      * to append.  If < 0, then append all
  1684.                      * of string, up to null at end. */
  1685. {
  1686.     int newSize;
  1687.     char *newString, *dst, *end;
  1688.  
  1689.     if (length < 0) {
  1690.     length = strlen(string);
  1691.     }
  1692.     newSize = length + dsPtr->length;
  1693.  
  1694.     /*
  1695.      * Allocate a larger buffer for the string if the current one isn't
  1696.      * large enough.  Allocate extra space in the new buffer so that there
  1697.      * will be room to grow before we have to allocate again.
  1698.      */
  1699.  
  1700.     if (newSize >= dsPtr->spaceAvl) {
  1701.     dsPtr->spaceAvl = newSize*2;
  1702.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  1703.     memcpy((VOID *)newString, (VOID *) dsPtr->string,
  1704.         (size_t) dsPtr->length);
  1705.     if (dsPtr->string != dsPtr->staticSpace) {
  1706.         ckfree(dsPtr->string);
  1707.     }
  1708.     dsPtr->string = newString;
  1709.     }
  1710.  
  1711.     /*
  1712.      * Copy the new string into the buffer at the end of the old
  1713.      * one.
  1714.      */
  1715.  
  1716.     for (dst = dsPtr->string + dsPtr->length, end = string+length;
  1717.         string < end; string++, dst++) {
  1718.     *dst = *string;
  1719.     }
  1720.     *dst = 0;
  1721.     dsPtr->length += length;
  1722.     return dsPtr->string;
  1723. }
  1724.  
  1725. /*
  1726.  *----------------------------------------------------------------------
  1727.  *
  1728.  * Tcl_DStringAppendElement --
  1729.  *
  1730.  *    Append a list element to the current value of a dynamic string.
  1731.  *
  1732.  * Results:
  1733.  *    The return value is a pointer to the dynamic string's new value.
  1734.  *
  1735.  * Side effects:
  1736.  *    String is reformatted as a list element and added to the current
  1737.  *    value of the string.  Memory gets reallocated if needed to
  1738.  *    accomodate the string's new size.
  1739.  *
  1740.  *----------------------------------------------------------------------
  1741.  */
  1742.  
  1743. char *
  1744. Tcl_DStringAppendElement(dsPtr, string)
  1745.     register Tcl_DString *dsPtr;    /* Structure describing dynamic
  1746.                      * string. */
  1747.     char *string;            /* String to append.  Must be
  1748.                      * null-terminated. */
  1749. {
  1750.     int newSize, flags;
  1751.     char *dst, *newString;
  1752.  
  1753.     newSize = Tcl_ScanElement(string, &flags) + dsPtr->length + 1;
  1754.  
  1755.     /*
  1756.      * Allocate a larger buffer for the string if the current one isn't
  1757.      * large enough.  Allocate extra space in the new buffer so that there
  1758.      * will be room to grow before we have to allocate again.
  1759.      * SPECIAL NOTE: must use memcpy, not strcpy, to copy the string
  1760.      * to a larger buffer, since there may be embedded NULLs in the
  1761.      * string in some cases.
  1762.      */
  1763.  
  1764.     if (newSize >= dsPtr->spaceAvl) {
  1765.     dsPtr->spaceAvl = newSize*2;
  1766.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  1767.     memcpy((VOID *) newString, (VOID *) dsPtr->string,
  1768.         (size_t) dsPtr->length);
  1769.     if (dsPtr->string != dsPtr->staticSpace) {
  1770.         ckfree(dsPtr->string);
  1771.     }
  1772.     dsPtr->string = newString;
  1773.     }
  1774.  
  1775.     /*
  1776.      * Convert the new string to a list element and copy it into the
  1777.      * buffer at the end, with a space, if needed.
  1778.      */
  1779.  
  1780.     dst = dsPtr->string + dsPtr->length;
  1781.     if (TclNeedSpace(dsPtr->string, dst)) {
  1782.     *dst = ' ';
  1783.     dst++;
  1784.     dsPtr->length++;
  1785.     }
  1786.     dsPtr->length += Tcl_ConvertElement(string, dst, flags);
  1787.     return dsPtr->string;
  1788. }
  1789.  
  1790. /*
  1791.  *----------------------------------------------------------------------
  1792.  *
  1793.  * Tcl_DStringSetLength --
  1794.  *
  1795.  *    Change the length of a dynamic string.  This can cause the
  1796.  *    string to either grow or shrink, depending on the value of
  1797.  *    length.
  1798.  *
  1799.  * Results:
  1800.  *    None.
  1801.  *
  1802.  * Side effects:
  1803.  *    The length of dsPtr is changed to length and a null byte is
  1804.  *    stored at that position in the string.  If length is larger
  1805.  *    than the space allocated for dsPtr, then a panic occurs.
  1806.  *
  1807.  *----------------------------------------------------------------------
  1808.  */
  1809.  
  1810. void
  1811. Tcl_DStringSetLength(dsPtr, length)
  1812.     register Tcl_DString *dsPtr;    /* Structure describing dynamic
  1813.                      * string. */
  1814.     int length;                /* New length for dynamic string. */
  1815. {
  1816.     if (length < 0) {
  1817.     length = 0;
  1818.     }
  1819.     if (length >= dsPtr->spaceAvl) {
  1820.     char *newString;
  1821.  
  1822.     dsPtr->spaceAvl = length+1;
  1823.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  1824.  
  1825.     /*
  1826.      * SPECIAL NOTE: must use memcpy, not strcpy, to copy the string
  1827.      * to a larger buffer, since there may be embedded NULLs in the
  1828.      * string in some cases.
  1829.      */
  1830.  
  1831.     memcpy((VOID *) newString, (VOID *) dsPtr->string,
  1832.         (size_t) dsPtr->length);
  1833.     if (dsPtr->string != dsPtr->staticSpace) {
  1834.         ckfree(dsPtr->string);
  1835.     }
  1836.     dsPtr->string = newString;
  1837.     }
  1838.     dsPtr->length = length;
  1839.     dsPtr->string[length] = 0;
  1840. }
  1841.  
  1842. /*
  1843.  *----------------------------------------------------------------------
  1844.  *
  1845.  * Tcl_DStringFree --
  1846.  *
  1847.  *    Frees up any memory allocated for the dynamic string and
  1848.  *    reinitializes the string to an empty state.
  1849.  *
  1850.  * Results:
  1851.  *    None.
  1852.  *
  1853.  * Side effects:
  1854.  *    The previous contents of the dynamic string are lost, and
  1855.  *    the new value is an empty string.
  1856.  *
  1857.  *----------------------------------------------------------------------
  1858.  */
  1859.  
  1860. void
  1861. Tcl_DStringFree(dsPtr)
  1862.     register Tcl_DString *dsPtr;    /* Structure describing dynamic
  1863.                      * string. */
  1864. {
  1865.     if (dsPtr->string != dsPtr->staticSpace) {
  1866.     ckfree(dsPtr->string);
  1867.     }
  1868.     dsPtr->string = dsPtr->staticSpace;
  1869.     dsPtr->length = 0;
  1870.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1871.     dsPtr->staticSpace[0] = 0;
  1872. }
  1873.  
  1874. /*
  1875.  *----------------------------------------------------------------------
  1876.  *
  1877.  * Tcl_DStringResult --
  1878.  *
  1879.  *    This procedure moves the value of a dynamic string into an
  1880.  *    interpreter as its result.  The string itself is reinitialized
  1881.  *    to an empty string.
  1882.  *
  1883.  * Results:
  1884.  *    None.
  1885.  *
  1886.  * Side effects:
  1887.  *    The string is "moved" to interp's result, and any existing
  1888.  *    result for interp is freed up.  DsPtr is reinitialized to
  1889.  *    an empty string.
  1890.  *
  1891.  *----------------------------------------------------------------------
  1892.  */
  1893.  
  1894. void
  1895. Tcl_DStringResult(interp, dsPtr)
  1896.     Tcl_Interp *interp;            /* Interpreter whose result is to be
  1897.                      * reset. */
  1898.     Tcl_DString *dsPtr;            /* Dynamic string that is to become
  1899.                      * the result of interp. */
  1900. {
  1901.     Tcl_ResetResult(interp);
  1902.     if (dsPtr->string != dsPtr->staticSpace) {
  1903.     interp->result = dsPtr->string;
  1904.     interp->freeProc = TCL_DYNAMIC;
  1905.     } else if (dsPtr->length < TCL_RESULT_SIZE) {
  1906.     interp->result = ((Interp *) interp)->resultSpace;
  1907.     strcpy(interp->result, dsPtr->string);
  1908.     } else {
  1909.     Tcl_SetResult(interp, dsPtr->string, TCL_VOLATILE);
  1910.     }
  1911.     dsPtr->string = dsPtr->staticSpace;
  1912.     dsPtr->length = 0;
  1913.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1914.     dsPtr->staticSpace[0] = 0;
  1915. }
  1916.  
  1917. /*
  1918.  *----------------------------------------------------------------------
  1919.  *
  1920.  * Tcl_DStringGetResult --
  1921.  *
  1922.  *    This procedure moves the result of an interpreter into a
  1923.  *    dynamic string.
  1924.  *
  1925.  * Results:
  1926.  *    None.
  1927.  *
  1928.  * Side effects:
  1929.  *    The interpreter's result is cleared, and the previous contents
  1930.  *    of dsPtr are freed.
  1931.  *
  1932.  *----------------------------------------------------------------------
  1933.  */
  1934.  
  1935. void
  1936. Tcl_DStringGetResult(interp, dsPtr)
  1937.     Tcl_Interp *interp;            /* Interpreter whose result is to be
  1938.                      * reset. */
  1939.     Tcl_DString *dsPtr;            /* Dynamic string that is to become
  1940.                      * the result of interp. */
  1941. {
  1942.     Interp *iPtr = (Interp *) interp;
  1943.     if (dsPtr->string != dsPtr->staticSpace) {
  1944.     ckfree(dsPtr->string);
  1945.     }
  1946.     dsPtr->length = strlen(iPtr->result);
  1947.     if (iPtr->freeProc != NULL) {
  1948.     if ((iPtr->freeProc == TCL_DYNAMIC)
  1949.         || (iPtr->freeProc == (Tcl_FreeProc *) free)) {
  1950.         dsPtr->string = iPtr->result;
  1951.         dsPtr->spaceAvl = dsPtr->length+1;
  1952.     } else {
  1953.         dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length+1));
  1954.         strcpy(dsPtr->string, iPtr->result);
  1955.         (*iPtr->freeProc)(iPtr->result);
  1956.     }
  1957.     dsPtr->spaceAvl = dsPtr->length+1;
  1958.     iPtr->freeProc = NULL;
  1959.     } else {
  1960.     if (dsPtr->length < TCL_DSTRING_STATIC_SIZE) {
  1961.         dsPtr->string = dsPtr->staticSpace;
  1962.         dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1963.     } else {
  1964.         dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length + 1));
  1965.         dsPtr->spaceAvl = dsPtr->length + 1;
  1966.     }
  1967.     strcpy(dsPtr->string, iPtr->result);
  1968.     }
  1969.     iPtr->result = iPtr->resultSpace;
  1970.     iPtr->resultSpace[0] = 0;
  1971. }
  1972.  
  1973. /*
  1974.  *----------------------------------------------------------------------
  1975.  *
  1976.  * Tcl_DStringStartSublist --
  1977.  *
  1978.  *    This procedure adds the necessary information to a dynamic
  1979.  *    string (e.g. " {" to start a sublist.  Future element
  1980.  *    appends will be in the sublist rather than the main list.
  1981.  *
  1982.  * Results:
  1983.  *    None.
  1984.  *
  1985.  * Side effects:
  1986.  *    Characters get added to the dynamic string.
  1987.  *
  1988.  *----------------------------------------------------------------------
  1989.  */
  1990.  
  1991. void
  1992. Tcl_DStringStartSublist(dsPtr)
  1993.     Tcl_DString *dsPtr;            /* Dynamic string. */
  1994. {
  1995.     if (TclNeedSpace(dsPtr->string, dsPtr->string + dsPtr->length)) {
  1996.     Tcl_DStringAppend(dsPtr, " {", -1);
  1997.     } else {
  1998.     Tcl_DStringAppend(dsPtr, "{", -1);
  1999.     }
  2000. }
  2001.  
  2002. /*
  2003.  *----------------------------------------------------------------------
  2004.  *
  2005.  * Tcl_DStringEndSublist --
  2006.  *
  2007.  *    This procedure adds the necessary characters to a dynamic
  2008.  *    string to end a sublist (e.g. "}").  Future element appends
  2009.  *    will be in the enclosing (sub)list rather than the current
  2010.  *    sublist.
  2011.  *
  2012.  * Results:
  2013.  *    None.
  2014.  *
  2015.  * Side effects:
  2016.  *    None.
  2017.  *
  2018.  *----------------------------------------------------------------------
  2019.  */
  2020.  
  2021. void
  2022. Tcl_DStringEndSublist(dsPtr)
  2023.     Tcl_DString *dsPtr;            /* Dynamic string. */
  2024. {
  2025.     Tcl_DStringAppend(dsPtr, "}", -1);
  2026. }
  2027.  
  2028. /*
  2029.  *----------------------------------------------------------------------
  2030.  *
  2031.  * Tcl_PrintDouble --
  2032.  *
  2033.  *    Given a floating-point value, this procedure converts it to
  2034.  *    an ASCII string using.
  2035.  *
  2036.  * Results:
  2037.  *    The ASCII equivalent of "value" is written at "dst".  It is
  2038.  *    written using the current precision, and it is guaranteed to
  2039.  *    contain a decimal point or exponent, so that it looks like
  2040.  *    a floating-point value and not an integer.
  2041.  *
  2042.  * Side effects:
  2043.  *    None.
  2044.  *
  2045.  *----------------------------------------------------------------------
  2046.  */
  2047.  
  2048. void
  2049. Tcl_PrintDouble(interp, value, dst)
  2050.     Tcl_Interp *interp;            /* Interpreter whose tcl_precision
  2051.                      * variable controls printing. */
  2052.     double value;            /* Value to print as string. */
  2053.     char *dst;                /* Where to store converted value;
  2054.                      * must have at least TCL_DOUBLE_SPACE
  2055.                      * characters. */
  2056. {
  2057.     register char *p;
  2058.     sprintf(dst, ((Interp *) interp)->pdFormat, value);
  2059.  
  2060.     /*
  2061.      * If the ASCII result looks like an integer, add ".0" so that it
  2062.      * doesn't look like an integer anymore.  This prevents floating-point
  2063.      * values from being converted to integers unintentionally.
  2064.      */
  2065.  
  2066.     for (p = dst; *p != 0; p++) {
  2067.     if ((*p == '.') || (isalpha(UCHAR(*p)))) {
  2068.         return;
  2069.     }
  2070.     }
  2071.     p[0] = '.';
  2072.     p[1] = '0';
  2073.     p[2] = 0;
  2074. }
  2075.  
  2076. #ifndef STk_CODE
  2077. /*
  2078.  *----------------------------------------------------------------------
  2079.  *
  2080.  * TclPrecTraceProc --
  2081.  *
  2082.  *    This procedure is invoked whenever the variable "tcl_precision"
  2083.  *    is written.
  2084.  *
  2085.  * Results:
  2086.  *    Returns NULL if all went well, or an error message if the
  2087.  *    new value for the variable doesn't make sense.
  2088.  *
  2089.  * Side effects:
  2090.  *    If the new value doesn't make sense then this procedure
  2091.  *    undoes the effect of the variable modification.  Otherwise
  2092.  *    it modifies the format string that's used by Tcl_PrintDouble.
  2093.  *
  2094.  *----------------------------------------------------------------------
  2095.  */
  2096.  
  2097.     /* ARGSUSED */
  2098. char *
  2099. TclPrecTraceProc(clientData, interp, name1, name2, flags)
  2100.     ClientData clientData;    /* Not used. */
  2101.     Tcl_Interp *interp;        /* Interpreter containing variable. */
  2102.     char *name1;        /* Name of variable. */
  2103.     char *name2;        /* Second part of variable name. */
  2104.     int flags;            /* Information about what happened. */
  2105. {
  2106.     register Interp *iPtr = (Interp *) interp;
  2107.     char *value, *end;
  2108.     int prec;
  2109.  
  2110.     /*
  2111.      * If the variable is unset, then recreate the trace and restore
  2112.      * the default value of the format string.
  2113.      */
  2114.  
  2115.     if (flags & TCL_TRACE_UNSETS) {
  2116.     if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
  2117.         Tcl_TraceVar2(interp, name1, name2,
  2118.             TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
  2119.             TclPrecTraceProc, clientData);
  2120.     }
  2121.     strcpy(iPtr->pdFormat, DEFAULT_PD_FORMAT);
  2122.     iPtr->pdPrec = DEFAULT_PD_PREC;
  2123.     return (char *) NULL;
  2124.     }
  2125.  
  2126.     value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY);
  2127.     if (value == NULL) {
  2128.     value = "";
  2129.     }
  2130.     prec = strtoul(value, &end, 10);
  2131.     if ((prec <= 0) || (prec > TCL_MAX_PREC) || (prec > 100) ||
  2132.         (end == value) || (*end != 0)) {
  2133.     char oldValue[10];
  2134.  
  2135.     sprintf(oldValue, "%d", iPtr->pdPrec);
  2136.     Tcl_SetVar2(interp, name1, name2, oldValue, flags & TCL_GLOBAL_ONLY);
  2137.     return "improper value for precision";
  2138.     }
  2139.     sprintf(iPtr->pdFormat, "%%.%dg", prec);
  2140.     iPtr->pdPrec = prec;
  2141.     return (char *) NULL;
  2142. }
  2143. #endif
  2144.  
  2145. /*
  2146.  *----------------------------------------------------------------------
  2147.  *
  2148.  * TclNeedSpace --
  2149.  *
  2150.  *    This procedure checks to see whether it is appropriate to
  2151.  *    add a space before appending a new list element to an
  2152.  *    existing string.
  2153.  *
  2154.  * Results:
  2155.  *    The return value is 1 if a space is appropriate, 0 otherwise.
  2156.  *
  2157.  * Side effects:
  2158.  *    None.
  2159.  *
  2160.  *----------------------------------------------------------------------
  2161.  */
  2162.  
  2163. int
  2164. TclNeedSpace(start, end)
  2165.     char *start;        /* First character in string. */
  2166.     char *end;            /* End of string (place where space will
  2167.                  * be added, if appropriate). */
  2168. {
  2169.     /*
  2170.      * A space is needed unless either
  2171.      * (a) we're at the start of the string, or
  2172.      * (b) the trailing characters of the string consist of one or more
  2173.      *     open curly braces preceded by a space or extending back to
  2174.      *     the beginning of the string.
  2175.      * (c) the trailing characters of the string consist of a space
  2176.      *       preceded by a character other than backslash.
  2177.      */
  2178.  
  2179.     if (end == start) {
  2180.     return 0;
  2181.     }
  2182.     end--;
  2183.     if (*end != '{') {
  2184.     if (isspace(UCHAR(*end)) && ((end == start) || (end[-1] != '\\'))) {
  2185.         return 0;
  2186.     }
  2187.     return 1;
  2188.     }
  2189.     do {
  2190.     if (end == start) {
  2191.         return 0;
  2192.     }
  2193.     end--;
  2194.     } while (*end == '{');
  2195.     if (isspace(UCHAR(*end))) {
  2196.     return 0;
  2197.     }
  2198.     return 1;
  2199. }
  2200.